home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 12 - 1996 / 12.12 Dec 96 / Fat Binaries / MoveDataƒ / DSUserProcs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-02-25  |  19.2 KB  |  634 lines  |  [TEXT/R*ch]

  1. /******************************************************************************
  2. **
  3. **  Project Name:    DropShell
  4. **     File Name:    DSUserProcs.c
  5. **
  6. **   Description:    Specific AppleEvent handlers used by the DropBox
  7. **
  8. *******************************************************************************
  9. **                       A U T H O R   I D E N T I T Y
  10. *******************************************************************************
  11. **
  12. **    Initials    Name
  13. **    --------    -----------------------------------------------
  14. **    LDR            Leonard Rosenthol
  15. **    MTC            Marshall Clow
  16. **    SCS            Stephan Somogyi
  17. **
  18. *******************************************************************************
  19. **                      R E V I S I O N   H I S T O R Y
  20. *******************************************************************************
  21. **
  22. **      Date        Time    Author    Description
  23. **    --------    -----    ------    ---------------------------------------------
  24. **    06/23/94            LDR        Added support for ProcessItem and ProcessFolder handling
  25. **    02/20/94            LDR        Modified Preflight & Postflight to take item count
  26. **    01/25/92            LDR        Removed the use of const on the userDataHandle
  27. **    12/09/91            LDR        Added the new SelectFile userProc
  28. **                                Added the new Install & DisposeUserGlobals procs
  29. **                                Modified PostFlight to only autoquit on odoc, not pdoc
  30. **    11/24/91            LDR        Added the userProcs for pdoc handler
  31. **                                Cleaned up the placement of braces
  32. **                                Added the passing of a userDataHandle
  33. **    10/29/91            SCS        Changes for THINK C 5
  34. **    10/28/91            LDR        Officially renamed DropShell (from QuickShell)
  35. **                                Added a bunch of comments for clarification
  36. **    10/06/91    00:02    MTC        Converted to MPW C
  37. **    04/09/91    00:02    LDR        Added to Projector
  38. **
  39. ******************************************************************************/
  40.  
  41. #include <StandardFile.h>
  42.  
  43. #include "DSGlobals.h"
  44. #include "DSUserProcs.h"
  45.  
  46. // Static Prototypes
  47. static     OSErr ProcessItem(FSSpecPtr myFSSPtr);
  48. static  OSErr ReverseProcessItem(FSSpecPtr myFSSPtr);
  49. static     OSErr AddRegistrationInfo(FSSpecPtr myFSSPtr);
  50. static     OSErr ProcessFolder(FSSpecPtr myFSSPtr);
  51. static    OSErr UpdateCFRG(short resRef,Byte fragmentType, Byte fragmentLocation,
  52.                          long fragmentOffset, long fragmentLength);
  53. static short isPressed(unsigned short key );
  54.  
  55. extern    void DoUpdate(EventRecord *event);
  56.  
  57. Handle        gMessage;
  58.  
  59. /*
  60.     Uncomment this line if you want each item of a dropped folder processed
  61.     as an individual item
  62. */
  63. // #define qWalkFolders
  64.  
  65.  
  66. /*
  67.     This routine is called during init time.
  68.     
  69.     It allows you to install more AEVT Handlers beyond the standard four
  70. */
  71. #pragma segment Main
  72. pascal void InstallOtherEvents (void) {
  73. }
  74.  
  75.  
  76. /*    
  77.     This routine is called when an OAPP event is received.
  78.     
  79.     Currently, all it does is set the gOApped flag, so you know that
  80.     you were called initally with no docs, and therefore you shouldn't 
  81.     quit when done processing any following odocs.
  82. */
  83. #pragma segment Main
  84. pascal void OpenApp (void) 
  85. {
  86.     gOApped = true;
  87.     DoUpdate(&gEvent);
  88. }
  89.  
  90.  
  91. /*    
  92.     This routine is called when an QUIT event is received.
  93.     
  94.     We simply set the global done flag so that the main event loop can
  95.     gracefully exit.  We DO NOT call ExitToShell for two reasons:
  96.     1) It is a pretty ugly thing to do, but more importantly
  97.     2) The Apple event manager will get REAL upset!
  98. */
  99. #pragma segment Main
  100. pascal void QuitApp (void) {
  101.     gDone = true;    /*    All Done! */
  102. }
  103.  
  104.  
  105. /*    
  106.     This routine is the first one called when an ODOC or PDOC event is received.
  107.     
  108.     In this routine you would place code used to setup structures, etc. 
  109.     which would be used in a 'for all docs' situation (like "Archive all
  110.     dropped files")
  111.  
  112.     Obviously, the opening boolean tells you whether you should be opening
  113.     or printing these files based on the type of event recieved.
  114.     
  115.     NEW IN 2.0!
  116.     The itemCount parameter is simply the number of items that were dropped on
  117.     the application and that you will be processing.  This gives you the ability
  118.     to do a single preflight for memory allocation needs, rather than doing it
  119.     once for each item as in previous versions.
  120.     
  121.     userDataHandle is a handle that you can create & use to store your own
  122.     data structs.  This dataHandle will be passed around to the other 
  123.     odoc/pdoc routines so that you can get at your data without using
  124.     globals - just like the new StandardFile.  
  125.     
  126.     We also return a boolean to tell the caller if you support this type
  127.     of event.  By default, our dropboxes don't support the pdoc, so when
  128.     opening is FALSE, we return FALSE to let the caller send back the
  129.     proper error code to the AEManager.
  130.  
  131. */
  132. #pragma segment Main
  133. pascal Boolean PreFlightDocs (Boolean opening, short itemCount, Handle *userDataHandle) 
  134. {
  135.  
  136.     if (isPressed(kControlKeyScanCode))
  137.         gAddRegistrationInfoOnly = true;
  138.  
  139.     if (isPressed(kOptionKeyScanCode))
  140.         gReverseOperation = true;
  141.     else
  142.         gReverseOperation = false;
  143.  
  144.     return opening;        // we support opening, but not printing - see above
  145. }
  146.  
  147.  
  148. /*    
  149.     This routine is called for each file passed in the ODOC event.
  150.     
  151.     In this routine you would place code for processing each file/folder/disk that
  152.     was dropped on top of you.
  153.     
  154.     You will probably want to remove the #pragma unused (currently there to fool the compiler!)
  155. */
  156. #pragma segment Main
  157. pascal void OpenDoc ( FSSpecPtr myFSSPtr, Boolean opening, Handle userDataHandle ) {
  158. #pragma unused ( myFSSPtr )
  159. #pragma unused ( opening )
  160. #pragma unused ( userDataHandle )
  161.     OSErr    err = noErr;
  162.     
  163.     
  164.     #ifdef qWalkFolders
  165.     /*
  166.         For this case we need to determine if the FSSpec is a file or folder.
  167.         If it's a folder, we then need to process each item in that folder,
  168.         otherwise just process the item.
  169.     */
  170.     if (FSpIsFolder(myFSSPtr))
  171.         err = ProcessFolder(myFSSPtr);
  172.     else
  173.         err = ProcessItem(myFSSPtr);
  174.     #else
  175.     /*
  176.         For this case we just call ProcessItem on the FSSpec above.
  177.     */
  178.     err = ProcessItem(myFSSPtr);
  179.     #endif
  180.     
  181.     // you should probably do something if you get back an error ;)
  182. }
  183.  
  184.  
  185. /*    
  186.     This routine is the last routine called as part of an ODOC event.
  187.     
  188.     In this routine you would place code to process any structures, etc. 
  189.     that you setup in the PreflightDocs routine.
  190.  
  191.     NEW IN 2.0!
  192.     The itemCount parameter was the number of items that you processed.
  193.     It is passed here just in case you need it ;)  
  194.     
  195.     If you created a userDataHandle in the PreFlightDocs routines, this is
  196.     the place to dispose of it since the Shell will NOT do it for you!
  197.     
  198.     You will probably want to remove the #pragma unusued (currently there to fool the compiler!)
  199. */
  200. #pragma segment Main
  201. pascal void PostFlightDocs ( Boolean opening, short itemCount, Handle userDataHandle ) {
  202. #pragma unused ( opening )
  203. #pragma unused ( itemCount )
  204. #pragma unused ( userDataHandle )
  205.  
  206.     if ( (opening) && (!gOApped) )
  207.         gDone = true;    //    close everything up!
  208.  
  209.     /*
  210.         The reason we do not auto quit is based on a recommendation in the
  211.         Apple event Registry which specifically states that you should NOT
  212.         quit on a 'pdoc' as the Finder will send you a 'quit' when it is 
  213.         ready for you to do so.
  214.     */
  215. }
  216.  
  217.  
  218.  
  219. static    OSErr UpdateCFRG(short resRef,Byte fragmentType, Byte fragmentLocation,
  220.                          long fragmentOffset, long fragmentLength)
  221. {
  222.     codeFragRecHandle    cfrgHndl;
  223.     codeFragRecPtr        cfrgRecPtr;
  224.     
  225.     OSErr    theError = -1;
  226.     
  227.     cfrgHndl = (codeFragRecHandle) Get1Resource('cfrg',0);
  228.     
  229.     if (cfrgHndl != NULL)
  230.     {
  231.         HLock((Handle) cfrgHndl);
  232.         (**cfrgHndl).fragArray[0].TypeOfFrag        = fragmentType;
  233.         (**cfrgHndl).fragArray[0].LocationOfFrag    = fragmentLocation;
  234.         
  235.         (**cfrgHndl).fragArray[0].OffsetToFrag        = fragmentOffset;
  236.         (**cfrgHndl).fragArray[0].LengthOfFrag        = fragmentLength;
  237.  
  238. //        (**cfrgHndl).fragArray[0].OffsetToFrag        = kPowerPCCode;
  239. //        (**cfrgHndl).fragArray[0].LengthOfFrag        = kPowerPCID;
  240.                         
  241.         HUnlock((Handle) cfrgHndl);
  242.         ChangedResource((Handle) cfrgHndl);
  243.         UpdateResFile(resRef);
  244.         ReleaseResource((Handle) cfrgHndl);
  245.         return noErr;
  246.  
  247.     }
  248.     return theError;
  249. }
  250.  
  251. //A simple utility to check if a particular key is pressed
  252. //key is any keyboard scan code 0 -127
  253. static short isPressed(unsigned short key )
  254. {
  255.     unsigned char km[16];
  256.  
  257.     GetKeys( (unsigned long *) km);    //rs Note universal headers 2.1 changed this to unsigned
  258.     return ( ( km[key>>3] >> (key & 7) ) & 1);
  259. }
  260.  
  261.  
  262. /*
  263.     This routine gets called for each item (which could be either a file or a folder)
  264.     that the caller wants dropped.  The determining factor is the definition of the 
  265.     qWalkFolder compiler directive.   Either way, the item in question should be
  266.     processed as a single item and not "dissected" into component units (like subfiles
  267.     of a folder!)
  268. */
  269. static OSErr ProcessItem(FSSpecPtr myFSSPtr)
  270. {
  271.     OSErr    err = noErr;
  272.     short    refNum;
  273.     short    resRef;
  274.     long    logEOF;
  275.     long    count;
  276.     Handle    POWER_PC_CODE;
  277.     short    resultCode;
  278.     short    itemHit;
  279.     
  280.  
  281.     if (gAddRegistrationInfoOnly)
  282.     {
  283.         return(AddRegistrationInfo(myFSSPtr));
  284.     }
  285.  
  286.     if (gReverseOperation)
  287.     {
  288.         return(ReverseProcessItem(myFSSPtr));
  289.     }
  290.     
  291.     err = FSpOpenDF(myFSSPtr, fsRdWrPerm, &refNum);        //Open the Data fork containing the
  292.     if (err == noErr)                                    //PowerPC code.
  293.     {
  294.         resRef = FSpOpenResFile(myFSSPtr,fsRdWrPerm);    //Open the Resource fork as
  295.         if (resRef != -1)                                //we will adding a new resource to hold the powerPC code
  296.         {
  297.             err = GetEOF(refNum,&logEOF);
  298.             if (logEOF == 0)
  299.             {
  300.                 itemHit = Alert(kNoDataFork,nil);
  301.             }
  302.             else
  303.             {
  304.                 if (logEOF < kMaxResourceSize)            //Check to see we don't exceed the max resource size
  305.                 {                                        //as Power PC Applications can be very large 
  306.                     POWER_PC_CODE = Get1Resource(kPowerPCCode,kPowerPCID);
  307.                     if (POWER_PC_CODE != NULL)
  308.                     {
  309.                         RemoveResource(POWER_PC_CODE);        //remove PowerPc code in resource if it already exists
  310.                         UpdateResFile(resRef);                //update resource
  311.                     }
  312.                     
  313.                     POWER_PC_CODE = NewHandle(logEOF);        //allocate a buffer
  314.                     
  315.                     if (POWER_PC_CODE == NULL)
  316.                         POWER_PC_CODE = TempNewHandle(logEOF,&resultCode);    //Use system memory if possible
  317.                                                                             //this way you don't have to worry about
  318.                     if (POWER_PC_CODE != NULL)                                //setting an appropiate 'size' resource
  319.                     {                                                        
  320.                         count = logEOF;
  321.                         err = FSRead(refNum,&count,*POWER_PC_CODE);
  322.                         AddResource(POWER_PC_CODE,kPowerPCCode,kPowerPCID,"\pPPC Code");
  323.                         WriteResource(POWER_PC_CODE);
  324.                         UpdateResFile(resRef);
  325.                         ReleaseResource(POWER_PC_CODE);
  326.                         err = SetEOF(refNum,0);                //set the data fork to 0;
  327.                         err = UpdateCFRG(resRef,kUsageIsApplication,kFragmentInResource,kPowerPCCode,kPowerPCID);//update 'cfrg' resource to point to right location
  328.                     }
  329.                     else
  330.                         itemHit = Alert(kMemErrorID,NULL);
  331.                 }
  332.                 else
  333.                     itemHit = Alert(kTooBigID,NULL);    
  334.              }
  335.         }
  336.         err = FSClose(refNum);
  337.     }
  338.     else
  339.         itemHit = Alert(kDataForkError,NULL);
  340.         
  341.     return(err);
  342. }
  343.  
  344.  
  345. /*
  346.     Depending on whether the user held down the option key on application startup
  347.     This routine gets called for each item (which could be either a file or a folder)
  348.     that the caller wants dropped.  The determining factor is the definition of the 
  349.     qWalkFolder compiler directive.   Either way, the item in question should be
  350.     processed as a single item and not "dissected" into component units (like subfiles
  351.     of a folder!)
  352.  
  353. */
  354. static OSErr ReverseProcessItem(FSSpecPtr myFSSPtr)
  355. {
  356.     OSErr    err = noErr;
  357.     short    refNum;
  358.     short    resRef;
  359.     long    logEOF;
  360.     long    count;
  361.     Handle    POWER_PC_CODE;
  362.     short    resultCode;
  363.     short    itemHit;
  364.         
  365.     err = FSpOpenDF(myFSSPtr, fsRdWrPerm, &refNum);        //Open the Data fork containing the
  366.     if (err == noErr)                                    //PowerPC code.
  367.     {
  368.         resRef = FSpOpenResFile(myFSSPtr,fsRdWrPerm);    //Open the Resource fork as
  369.         if (resRef != -1)                                //we will adding a new resource to hold the powerPC code
  370.         {
  371.             err = GetEOF(refNum,&logEOF);
  372.             if (logEOF != 0)
  373.             {
  374.                 itemHit = Alert(kDataForkError,nil);
  375.             }
  376.             else
  377.             {
  378.                     POWER_PC_CODE = Get1Resource(kPowerPCCode,kPowerPCID);
  379.                     logEOF = GetHandleSize(POWER_PC_CODE);
  380.                     
  381.                     if (POWER_PC_CODE != NULL)
  382.                     {
  383.                         RemoveResource(POWER_PC_CODE);        //remove PowerPc code in resource if it already exists
  384.                         UpdateResFile(resRef);                //update resource
  385.                     }
  386.                                                         
  387.                     if (POWER_PC_CODE != NULL)                                
  388.                     {                                                        
  389.                         count = logEOF;
  390.                         err = FSWrite(refNum,&count,*POWER_PC_CODE);
  391.                         ReleaseResource(POWER_PC_CODE);
  392.                         err = UpdateCFRG(resRef,kUsageIsApplication,kFragmentInDataFork,kBeginningOfFragment,kWholeFork);            //update 'cfrg' resource to point to right location
  393.                     }
  394.                     else
  395.                         itemHit = Alert(kMemErrorID,NULL);
  396.                 }
  397.             }
  398.         }
  399.      else
  400.         itemHit = Alert(kDataForkError,NULL);
  401.         
  402.         err = FSClose(refNum);
  403.     return(err);
  404. }
  405.  
  406.  
  407. static OSErr AddRegistrationInfo(FSSpecPtr myFSSPtr)
  408. {
  409.     OSErr    err = noErr;
  410.     short    refNum;
  411.     short    resRef;
  412.     long    logEOF;
  413.     long    count;
  414.     Handle    POWER_PC_CODE;
  415.     short    resultCode;
  416.     short    itemHit;
  417.     
  418.     ProductRegistrationInfo  theData = {'DATA',911,TRUE,'X',"\p",'END'};
  419.     long    infoSize = sizeof(theData);
  420.     
  421.     err = FSpOpenDF(myFSSPtr, fsRdWrPerm, &refNum);        //Open the Data fork containing the
  422.  
  423.     if (err == noErr)                                    //PowerPC code.
  424.     {
  425.         err = GetEOF(refNum,&logEOF);
  426.         if (logEOF == 0)
  427.         {
  428.             itemHit = Alert(kNoDataFork,nil);
  429.         }
  430.         else
  431.         {
  432.             POWER_PC_CODE = NewHandle(logEOF);        //allocate a buffer
  433.             
  434.             if (POWER_PC_CODE == NULL)
  435.                 POWER_PC_CODE = TempNewHandle(logEOF,&resultCode);    //Use system memory if possible
  436.                                                                         //this way you don't have to worry about
  437.                 if (POWER_PC_CODE != NULL)                                //setting an appropiate 'size' resource
  438.                 {                                                        
  439.                     resRef = FSpOpenResFile(myFSSPtr,fsRdWrPerm);    //Open the Resource fork as
  440.                     if (resRef != -1)
  441.                     {
  442.                         count = logEOF;
  443.                         err = FSRead(refNum,&count,*POWER_PC_CODE);        //Read the PPC code
  444.                         err = SetFPos(refNum,fsFromStart,0);            //Reset the file mark to the beginning of the file
  445.                         PLstrcpy(theData.subliminalMessage,"\pThis Data Located before Start of PPC code fragment. ");
  446.                         err = FSWrite(refNum,&infoSize,&theData);        //Write my custom Data at the beginning of the file
  447.                         err = FSWrite(refNum,&count,*POWER_PC_CODE);    //Write out the PPC code
  448.                         PLstrcpy(theData.subliminalMessage,"\pThis Data after the Main PPC code fragment. ");
  449.                         err = FSWrite(refNum,&infoSize,&theData);        //Write my custom Data again at the end of the file
  450.                         err = UpdateCFRG(resRef,kUsageIsApplication,kOnDiskFlat,infoSize,kWholeFork);//update 'cfrg' resource to point to right location
  451.                         UpdateResFile(resRef);
  452.                     }
  453.                 }
  454.                 else
  455.                     itemHit = Alert(kMemErrorID,NULL);
  456.             }
  457.     }
  458.  
  459.     err = FSClose(refNum);
  460.     return(err);
  461. }
  462.  
  463. /*
  464.     This routine gets called for any folder (or disk) that the caller wants 
  465.     processed as a set of component items, instead of as a single entity.
  466.     The determining factor is the definition of the qWalkFolder compiler directive.
  467. */
  468. static OSErr ProcessFolder(FSSpecPtr myFSSPtr)
  469. {
  470.     OSErr        err = noErr;
  471.     short        index, oldIndex, localIndex;
  472.     FSSpec        localFSSpec, curFSSpec;
  473.     CInfoPBRec    cipb;
  474.     Str255        fName, vFName;
  475.     long        dirID, origDirID;
  476.     Boolean        foundPosition;
  477.  
  478.      // copy the source locally to avoid recursion problems
  479.      BlockMoveData(myFSSPtr, &localFSSpec, sizeof(FSSpec));
  480.      
  481.     //    get the dirID for THIS folder, not it's parent!
  482.     BlockMoveData(localFSSpec.name, fName, 32);
  483.     
  484.     cipb.hFileInfo.ioCompletion    = 0L;
  485.     cipb.hFileInfo.ioNamePtr    = fName;
  486.     cipb.hFileInfo.ioVRefNum    = localFSSpec.vRefNum;
  487.     cipb.hFileInfo.ioFDirIndex    = 0;    // use the dir & vRefNum;
  488.     cipb.hFileInfo.ioDirID        = localFSSpec.parID;
  489.     err = PBGetCatInfoSync(&cipb);
  490.     
  491.     if (!err) {        
  492.         origDirID = cipb.dirInfo.ioDrDirID; // copy the sucker
  493.         index = 1;
  494.                 
  495.         // index through all contents of this folder
  496.         while (err == noErr) {
  497.             dirID = origDirID;
  498.             localIndex = index;
  499.             fName [0] = 0;
  500.             cipb.hFileInfo.ioCompletion    = 0L;
  501.             cipb.hFileInfo.ioNamePtr    = fName;
  502.             cipb.hFileInfo.ioVRefNum    = localFSSpec.vRefNum;
  503.             cipb.hFileInfo.ioFDirIndex    = localIndex;    // use a real index
  504.             cipb.hFileInfo.ioDirID        = dirID;
  505.             err = PBGetCatInfoSync(&cipb);
  506.  
  507.             if (!err) {
  508.                 BlockMoveData(fName, curFSSpec.name, 32);
  509.                 curFSSpec.vRefNum    = cipb.hFileInfo.ioVRefNum;
  510.                 curFSSpec.parID        = dirID;
  511.             
  512.                 /*    
  513.                     Check to see if this entry is a folder.
  514.                 */
  515.                 if (cipb.hFileInfo.ioFlAttrib & ioDirMask) {
  516.                     err = ProcessFolder(&curFSSpec);
  517.                  } else
  518.                     err = ProcessItem(&curFSSpec);
  519.             
  520.                 /*    If we've had an error, get out! */
  521.                 if (err)    break;
  522.  
  523.                 // dirID = origDirID;    
  524.                 localIndex = index;    
  525.  
  526.                 /*    
  527.                     Now take into account new files being created
  528.                     in the current directory & messing up our index.
  529.                     See Dev.CD Vol. XI:Tools & Apps (Moof!):Misc Utilities:
  530.                     Disinfectant & Source 2.5.1:Sample:Notes:Scan Alg    
  531.                 */
  532.                 vFName [0] = 0;
  533.                 cipb.hFileInfo.ioCompletion    = 0L;
  534.                 cipb.hFileInfo.ioNamePtr    = vFName;
  535.                 cipb.hFileInfo.ioVRefNum    = localFSSpec.vRefNum;
  536.                 cipb.hFileInfo.ioFDirIndex    = localIndex;    // use a real index
  537.                 cipb.hFileInfo.ioDirID        = dirID;
  538.                 err = PBGetCatInfoSync(&cipb);
  539.                 oldIndex = index;
  540.                 if (!err) {
  541.                     /*    If they're equal - same place, go to next */
  542.                     if (EqualString (vFName, fName, false, false))
  543.                         index++;
  544.                 }
  545.                 
  546.                 /*    If we didn't advance, then perhaps a file was created or deleted */
  547.                 if (oldIndex == index) {
  548.                     oldIndex        = index;    /* save off the old */
  549.                     index            = 0;        /* and start at the beginning */
  550.                     err                = noErr;
  551.                     vFName [0]        = 0;
  552.                     foundPosition    = false;
  553.                     
  554.                     while (!foundPosition) {
  555.                         index++;
  556.                         vFName [0] = 0;
  557.                         cipb.hFileInfo.ioCompletion    = 0L;
  558.                         cipb.hFileInfo.ioNamePtr    = vFName;
  559.                         cipb.hFileInfo.ioVRefNum    = localFSSpec.vRefNum;
  560.                         cipb.hFileInfo.ioFDirIndex    = index;    /* now use a real index */
  561.                         cipb.hFileInfo.ioDirID        = dirID;
  562.                         err = PBGetCatInfoSync(&cipb);
  563.                         
  564.                         if (err == fnfErr) {  // we've just been deleted
  565.                             index = oldIndex;
  566.                             foundPosition = true;
  567.                             err = noErr;    // have to remember to reset this!
  568.                         }
  569.                         
  570.                     /*    found same file & same index position */
  571.                     /*    so try the next item */
  572.                         if ((!foundPosition) && EqualString(fName, vFName, false, false)) {
  573.                             index++;
  574.                             foundPosition = true;
  575.                         }
  576.                     }
  577.                 }
  578.             }
  579.         }
  580.     }
  581.     
  582.     return(err);
  583. }
  584.  
  585. /*
  586.     This routine is called when the user chooses "Select File…" from the
  587.     File Menu.
  588.     
  589.     Currently it simply calls the new StandardGetFile routine to have the
  590.     user select a single file (any type, numTypes = -1) and then calls the
  591.     SendODOCToSelf routine in order to process it.  
  592.             
  593.     The reason we send an odoc to ourselves is two fold: 1) it keeps the code
  594.     cleaner as all file openings go through the same process, and 2) if events
  595.     are ever recordable, the right things happen (this is called Factoring!)
  596.  
  597.     Modification of this routine to only select certain types of files, selection
  598.     of multiple files, and/or handling of folder & disk selection is left 
  599.     as an exercise to the reader.
  600. */
  601. pascal void SelectFile (void)
  602. {
  603.     StandardFileReply    stdReply;
  604.     SFTypeList            theTypeList;
  605.  
  606.     StandardGetFile(NULL, -1, theTypeList, &stdReply);
  607.     if (stdReply.sfGood)    // user did not cancel
  608.         SendODOCToSelf(&stdReply.sfFile);    // so send me an event!
  609. }
  610.  
  611. /*
  612.     This routine is called during the program's initialization and gives you
  613.     a chance to allocate or initialize any of your own globals that your
  614.     dropbox needs.
  615.     
  616.     You return a boolean value which determines if you were successful.
  617.     Returning false will cause DropShell to exit immediately.
  618. */
  619. pascal Boolean InitUserGlobals(void)
  620. {
  621.     gMessage = GetResource('TEXT',128);
  622.     return(true);    // nothing to do, it we must be successful!
  623. }
  624.  
  625. /*
  626.     This routine is called during the program's cleanup and gives you
  627.     a chance to deallocate any of your own globals that you allocated 
  628.     in the above routine.
  629. */
  630. pascal void DisposeUserGlobals(void)
  631. {
  632.     // nothing to do for our sample dropbox
  633. }
  634.